# -*- encoding: utf8 -*-

from datetime import datetime

from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.contrib.auth import login, logout, authenticate
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.utils.safestring import mark_safe

from reps.interns.forms import *
from reps.interns.models import *
from reps.interns.common import *
from reps.interns.helpers import teacher_only, teacher_or_dean_only
from reps.interns.helpers import verify_existence
from reps.interns.helpers import render, returnable, return_url

    
######################
# Account operations #
######################

def logout_view(request):
    logout(request)
    return HttpResponseRedirect('/')


def profile(request):
    return render('profile.html', request)


def register(request, spec_id=None):
    try:
        spec = Specialization.objects.get(id=spec_id)
        if request.method == 'POST':
            form = RegisterForm(data=request.POST, spec=spec)
            if form.is_valid():
                form.save()
                data = {'topic': 'Konto zarejestrowane',
                        'message': mark_safe('Możesz się teraz <a href="/accounts/login/">zalogować</a>. Hasło otrzymasz w wiadomości wysłanej na podany adres.')}
                return render('simple_message.html', request, data)
        else:
            form = RegisterForm(spec=spec)
        return render('register.html', request, {'spec': spec, 'form': form})
    except Specialization.DoesNotExist:
        pass
    return render('register.html', request, {'faculties': Faculty.objects.all()})


def reset_password(request):
    if request.method == 'POST':
        form = ResetPasswordForm(request.POST)
        if form.is_valid():
            form.save()
            data = {'topic': 'Hasło przywrócone',
                    'message': 'Jeżeli podałeś poprawny numer indeksu to hasło zostało przywrócone.'}
            return render('simple_message.html', request, data)
    else:
        form = ResetPasswordForm()
    return render('reset_password.html', request, {'form': form})


@login_required
def change_details(request, which=None):
    user = request.user
    if request.method == 'POST':
        if which == 'password':
            password_form = ChangePasswordForm(request.POST)
            email_form = ChangeEmailForm({'email': user.email})
            if password_form.is_valid():
                data = password_form.cleaned_data
                if user.check_password(data['old_password']):
                    user.set_password(data['password1'])
                    user.save()
                    return render('simple_message.html', request, 
                                  {'topic': 'Hasło zostało zmienione'})
                else:
                    return render('simple_message.html', request,
                                  {'topic': 'Wpisane hasło jest niepoprawne'})
        elif which == 'email':
            password_form = ChangePasswordForm()
            email_form = ChangeEmailForm(request.POST, initial={'email': user.email})
            if email_form.is_valid():
                user.email = email_form.cleaned_data['email']
                user.save()
                return render('simple_message.html', request,
                              {'topic': 'Adres e-mail został zmieniony'})
    else:
        password_form = ChangePasswordForm()
        email_form = ChangeEmailForm({'email': user.email})
    return render('change_details.html', request,
                  {'password_form': password_form, 'email_form': email_form})


@login_required
@verify_existence(Specialization, 'spec_id')
def select_specialization(request, spec_id=None, all=None):
    if all:
        try:
            del request.session['selected_specialization']
        except KeyError:
            pass
    else:
        spec_id = int(spec_id)
        spec = Specialization.objects.get(id=spec_id)
        if spec in request.user.get_profile().get_specializations():
            request.session['selected_specialization'] = spec
    return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))


#########
# Debug #
#########

def test(request):
    if request.method == 'POST':
        form = TestForm(request.POST)
    else:
        form = TestForm()
    return render_to_response('test.html', {'form': form})


def not_implemented_yet(request, **kargs):
    #print 'Not implemented yet. Args: ', kargs
    return render('not_implemented_yet.html', request)


################################
# Teacher's Students Interface #
################################

@login_required
@teacher_only
def new_student(request, teacher=None):
    if request.method == 'POST':
        form = NewStudentForm(request.POST)
        if form.is_valid():
            student = form.save()
            url = return_url(request, u'Student został dodany')
            return HttpResponseRedirect(url)
        else:
            return render('new_student.html', request, {'form': form})
    else:
        try:
            spec_id = request.session['selected_specialization'].id
            form = NewStudentForm(spec_id=spec_id)
        except:
            form = NewStudentForm()
        return render('new_student.html', request, {'form': form})


@login_required
@teacher_only
@returnable
def list_students(request, teacher=None):
    try:
        specs = [request.session['selected_specialization']]
    except:
        specs = teacher.specialization_set.all()
    return render('list_students.html', request,
                  {'specializations': specs})


def handle_students_file(f, cp):
    data = f.read().decode(cp)
    result = []
    if data.find('\r\n')!=-1:
        line_delimiter='\r\n'
    else:
        line_delimiter='\n'
    if data.find(':')!=-1:
        field_delimiter=':'
    else:
        field_delimiter=';'
    return [line.split(field_delimiter) for line in data.split(line_delimiter) if line]


@login_required
@teacher_only
def import_students(request, save=None, teacher=None):
    if save:
        specialization = request.session['imported_data_specialization']
        for i in request.session['imported_data']:
            Student.new(i[0], i[1], i[2], specialization)
        return render('simple_message.html', request,
                      {'topic': 'Import danych', 'message': 'Dane zaimportowane'})
    specialization_choices = tuple([(i.id, i.full_name)
                                    for i in teacher.specialization_set.all()])
    initial = {}
    if 'selected_specialization' in request.session:
        initial['specialization'] = request.session['selected_specialization'].id
    if request.method == 'POST':
        form = UploadStudentsFileForm(request.POST, request.FILES,
                                      initial=initial,
                                      choices=specialization_choices)
        if form.is_valid():
            try:
                codepage=request.POST['codepage']
                student_list = handle_students_file(request.FILES['file'], codepage)
                request.session['imported_data'] = student_list
                specialization = teacher.specialization_set.get(id=int(form.cleaned_data['specialization']))        # TODO: check for errors
                request.session['imported_data_specialization'] = specialization
                initial['codepage'] = form.cleaned_data['codepage']
                form = UploadStudentsFileForm(choices=specialization_choices,
                                              initial=initial)
                return render('import_students.html', request,
                              {'students': student_list, 'form': form})
            except UnicodeDecodeError:
                return render('import_students.html', request,
                              {'msg': u'Błędne kodowanie pliku!',
                               'students': [], 'form': form})
    else:
        form = UploadStudentsFileForm(initial=initial,
                                      choices=specialization_choices)
    return render('import_students.html', request, {'students': [], 'form': form})


@login_required
@teacher_only
@returnable
@verify_existence(Student, 'student_id')
def show_student(request, student_id=None, teacher=None):
    student = Student.objects.get(id=int(student_id))
    if teacher.can_edit_student(student):
        return render('show_student.html', request, {'student': student})
    else:
        return HttpResponseRedirect('/forbidden/')


@login_required
@teacher_only
@verify_existence(Student, 'student_id')
def edit_student(request, student_id=None, teacher=None):
    student = Student.objects.get(id=int(student_id))
    if teacher.can_edit_student(student):
        if request.method == 'POST':
            form = StudentForm(request.POST, student=student)
            if form.is_valid():
                form.save()
                url = return_url(request, u'Dane studenta zostały zapisane.')
                return HttpResponseRedirect(url)
        else:
            form = StudentForm(student=student)
        return render('edit_student.html', request, {'form': form})
    else:
        return HttpResponseRedirect('/forbidden/')


@login_required
@teacher_only
@verify_existence(Student, 'student_id')
def delete_student(request, undelete=False, student_id=None, teacher=None):
    student = Student.objects.get(id=int(student_id))
    if teacher.can_edit_student(student):
        user = student.profile.user
        if undelete:
            user.is_active = True
        else:
            user.is_active = False
        user.save()
        url = return_url(request, u'Student został usunięty.')
        return HttpResponseRedirect(url)
    else:
        return HttpResponseRedirect('/forbidden/')


############################
# Companies Interface CRUD #
############################

# TODO: usuwanie firm

@login_required
@returnable
def my_companies(request):
    branches = list(request.user.branch_set.filter(main_branch__isnull=True))
    for branch in request.user.branch_set.filter(main_branch__isnull=False):
        main = branch.main_branch
        if not main in branches:
            branches.append(main)
    return render('list_companies.html', request,
                  {'main_branches': branches,
                   'single_branch': False})


@login_required
@verify_existence(Branch, 'main_branch_id')
def new_company(request, main_branch_id=None):
    if request.method == 'POST':
        form = BranchForm(request.POST)
        if form.is_valid():
            branch = form.save(commit=False)
            branch.created_by = request.user
            branch.save()
            url = return_url(request, u'Firma została dodana.')
            return HttpResponseRedirect(url)
    else:
        if main_branch_id != None:
            form = BranchForm(initial={'main_branch': main_branch_id})
        else:
            form = BranchForm()
    return render('edit_company.html', request, {'form': form})


@login_required
@verify_existence(Branch, 'main_branch_id')
@returnable
def list_companies(request, main_branch_id=None):
    if main_branch_id:
        data = {'main_branches': [Branch.objects.get(id=main_branch_id)],
                'single_branch': True}
    else:
        data = {'main_branches': Branch.objects.filter(main_branch__isnull=True),
                'single_branch': False}
    return render('list_companies.html', request, data)


@login_required
@verify_existence(Branch, 'branch_id')
def show_company(request, branch_id=None):
    return render('show_company.html', request,
                  {'branch': Branch.objects.get(id=branch_id)})


@login_required
@verify_existence(Branch, 'branch_id')
def edit_company(request, branch_id=None):
    branch_id = int(branch_id)
    branch = Branch.objects.get(id=branch_id)
    if not request.user.teacher() and branch.created_by.id != request.user.id:
        return HttpResponseRedirect('/forbidden/')
    if request.method == 'POST':
        form = BranchForm(request.POST, instance=branch)
        if form.is_valid():
            branch = form.save(commit=False)
            branch.created_by = request.user
            branch.save()
            url = return_url(request, u'Dane firmy zostały zmienione.')
            return HttpResponseRedirect(url)
    else:
        form = BranchForm(instance=branch)
    return render('edit_company.html', request, {'form': form, 'branch': branch})


@login_required
@teacher_only
@verify_existence(Branch, 'branch_id')
def seize_company(request, branch_id=None, teacher=None):
    branch_id = int(branch_id)
    branch = Branch.objects.get(id=branch_id)
    branch.created_by = request.user
    branch.save()
    url = return_url(request, u'Dane firmy zostały przejęte.')
    return HttpResponseRedirect(url)


@login_required
@teacher_only
def seize_all_seizable_companies(request, teacher=None):
    userprofiles = UserProfile.objects.all()
    teachers = [el.user for el in userprofiles if not el.is_teacher() is False ]
    branches = Branch.objects.exclude(created_by__in=teachers)
    for branch in branches:
        branch.created_by = request.user
        branch.save()
    url = return_url(request, u'Dane firm zostały przejęte.')
    return HttpResponseRedirect(url)


#########################
# Training's Dates CRUD #
#########################

@login_required
@teacher_only
def generate_dates(request, teacher=None):
    specialization = request.session.get('selected_specialization', None)
    if request.method == 'POST':
        form = TrainingDateGenerationForm(request.POST)
        if form.is_valid():
            if specialization:
                specializations = [specialization]
            else:
                specializations = teacher.specialization_set.all()
            training_dates = form.generate_dates(specializations)
            for td in training_dates:
                td.save()
            url = return_url(request, u'Terminy praktyk zostały wygenerowane.')
            return HttpResponseRedirect(url)
    else:
        form = TrainingDateGenerationForm()
    return render('generate_dates.html', request,
                  {'form': form, 'specialization': specialization})


@login_required
@teacher_only
@returnable
def list_dates(request, teacher=None):
    try:
        specs = [request.session['selected_specialization']]
    except:
        specs = teacher.specialization_set.all()
    return render('list_dates.html', request,
                  {'specializations': specs})


@login_required
@teacher_only
@verify_existence(Training_Date, 'td_id')
def edit_date(request, td_id=None, teacher=None):
    td_id = int(td_id)
    training_date = Training_Date.objects.get(id=td_id)
    if request.method == 'POST':
        form = TrainingDateForm(request.POST, instance=training_date)
        if form.is_valid():
            form.save()
            url = return_url(request, u'Termin został zmieniony.')
            return HttpResponseRedirect(url)
    else:
        form = TrainingDateForm(instance=training_date)
    return render('edit_date.html', request,
                  {'form': form, 'training_date': training_date})


@login_required
@teacher_only
@verify_existence(Training_Date, 'td_id')
def delete_date(request, td_id=None, teacher=None):
    training_date = Training_Date.objects.get(id=td_id)
    specialization = training_date.specialization
    if not teacher.governs_specialization(specialization):
        return HttpResponseRedirect('/forbidden/')
    training_date.delete()
    url = return_url(request, u'Termin został usunięty.')
    return HttpResponseRedirect(url)


@login_required
@teacher_only
@verify_existence(Specialization, 'spec_id')
def new_date(request, spec_id=None, teacher=None):
    specialization = Specialization.objects.get(id=spec_id)
    if not teacher.governs_specialization(specialization):
        return HttpResponseRedirect('/forbidden/')
    if request.method == 'POST':
        form = TrainingDateForm(request.POST)
        if form.is_valid():
            training_date = form.save(commit=False)
            training_date.specialization = specialization
            training_date.save()
            url = return_url(request, u'Termin został dodany.')
            return HttpResponseRedirect(url)
    else:
        form = TrainingDateForm()
    return render('edit_date.html', request, {'form': form})


#################################
# Teacher's Trainings Interface #
#################################

@login_required
@teacher_only
@returnable
def list_trainings(request, teacher=None):
    try:
        specializations = [request.session['selected_specialization']]
    except:
        specializations = teacher.specialization_set.all()
    trainings = []
    for spec in specializations:
        for student in spec.student_set.all():
            trainings.extend(student.training_set.filter(is_archival=False))
    return render('list_trainings.html', request,
                  {'trainings': trainings})


@login_required
@teacher_only
def bulk_lock_trainings(request, teacher=None, unlock_all=False, switch_all=False):
    try:
        specializations = [request.session['selected_specialization']]
    except:
        specializations = teacher.specialization_set.all()
    for spec in specializations:
        for student in spec.student_set.all():
            if teacher.can_edit_student(student):
                trainings = student.training_set.filter(is_archival=False)
                for training in trainings:
                    if unlock_all:
                        training.locked = False
                    elif switch_all:
                        training.locked = not training.locked
                    else:
                        training.locked = True
                    training.save()
            else:
                return HttpResponseRedirect('/forbidden/')
    
    if unlock_all:
        message = u'Dane praktyk zostały odblokowane.'
    elif switch_all:
        message = u'Dane praktyk zablokowanych zostały odblokowane, a niezablokowanych - zablkowane.'
    else:
        message = u'Dane praktyk zostały zablokowane.'
    url = return_url(request, message)
    return HttpResponseRedirect(url)


@login_required
@teacher_only
@verify_existence(Training, 'training_id')
def lock_training(request, unlock=False, training_id=None, teacher=None):
    training_id = int(training_id)
    training = Training.objects.get(id=training_id)
    if teacher.can_edit_student(training.student):
        if unlock:
            training.locked = False
            message = u'Dane praktyki zostały odblokowane.'
        else:
            training.locked = True
            message = u'Dane praktyki zostały zablokowane.'
        training.save()
        url = return_url(request, message)
        return HttpResponseRedirect(url)
    else:
        return HttpResponseRedirect('/forbidden/')


@login_required
@teacher_only
@verify_existence(Training, 'training_id')
def mark_training(request, training_id=None, teacher=None):
    training_id = int(training_id)
    training = Training.objects.get(id=training_id)
    if teacher.can_edit_student(training.student):
        if request.method == 'POST':
            form = MarkTrainingFrom(request.POST,
                                    initial={'mark': training.mark,
                                             'pass_date': training.pass_date})
            if form.is_valid():
                training.is_archival = True
                if request.POST[u'submit'] == u'zalicz':
                    training.mark = form.cleaned_data['mark']
                    if form.cleaned_data['pass_date'] is None:
                        training.pass_date = datetime.today().date()
                    else:
                        training.pass_date = form.cleaned_data['pass_date']
                else:
                    training.pass_date = None
                training.save()
                url = return_url(request, u'Praktyka została oceniona.')
                return HttpResponseRedirect(url)
        else:
            if training.pass_date is None:
                date = datetime.today().date()
            else:
                date = training.pass_date
            form = MarkTrainingFrom(initial={'mark': training.mark,
                                             'pass_date': date})
        return render('mark_training.html', request, {'form': form})
    else:
        return HttpResponseRedirect('/forbidden/')


@login_required
@teacher_only
@verify_existence(Student, 'student_id')
def new_training(request, student_id=None, teacher=None):
    student = Student.objects.get(id=student_id)
    if not teacher.can_edit_student(student):
        return HttpResponseRedirect('/forbidden/')
    student.add_training()
    url = return_url(request, u'Praktyka zostały dodana.')
    return HttpResponseRedirect(url)


#####################
# Student Interface #
#####################

@login_required
@returnable
def student_trainings(request):
    trainings = []
    specialization = request.session.get('selected_specialization', None)
    for student in request.user.student(specialization):
        trainings += student.training_set.all()
    return render('list_student_trainings.html', request,
                  {'trainings': trainings})


@login_required
@verify_existence(Training, 'training_id')
def edit_student_training(request, training_id=None):
    training_id = int(training_id)
    training = Training.objects.get(id=training_id)
    teacher = request.user.teacher()
    if teacher: # editing as teacher
        if not teacher.can_edit_student(training.student):
            return HttpResponseRedirect('/forbidden/')
    elif training.student.user().id != request.user.id: # editing as student
        return HttpResponseRedirect('/forbidden/')
    if training.locked and not teacher:
        url = return_url(request, u'Dane praktyki zostały zablokowane i mogą być zmienione tylko przez Opiekuna praktyk.')
        return HttpResponseRedirect(url)
    if request.method == 'POST':
        form = TrainingForm(request.POST, instance=training)
        if form.is_valid():
            training = form.save(commit=False)
            training.save()
            url = return_url(request, u'Dane praktyki zostały zmienione.')
            return HttpResponseRedirect(url)
    else:
        form = TrainingForm(instance=training)
    return render('edit_training.html', request,
                  {'form': form, 'training': training})


@login_required
@verify_existence(Training, 'training_id')
def show_student_training(request, training_id=None):
    training_id = int(training_id)
    training = Training.objects.get(id=training_id)
    teacher = request.user.teacher()
    if teacher: # viewing as teacher
        if not teacher.can_edit_student(training.student):
            return HttpResponseRedirect('/forbidden/')
    elif training.student.user().id != request.user.id: # viewing as student
        return HttpResponseRedirect('/forbidden/')
    return render('show_training.html', request, {'training': training})


##########################################
# Teacher's and Dean's Archive Interface #
##########################################

class markable_archive_year_link_renderer:
    def __init__(self, marked_year=None):
        self.marked_year = marked_year

    def markable_archive_year_link(self, item):
        if self.marked_year!=None:
            if type(item)==type(0) and int(self.marked_year) == int(item):
                return u"<a href=\"/archive/list/"+unicode(item)+"/\"><b>"+unicode(item)+"</b></a>"
            elif (type(item)==type("") or type(item)==type(u"")):
                return u"<a href=\"/archive/list/\">"+unicode(item)+"</a>"
            else:
                return u"<a href=\"/archive/list/"+unicode(item)+"/\">"+unicode(item)+"</a>"
        else:
            if (type(item)==type("") or type(item)==type(u"")) and not item.isdigit():
                return u"<a href=\"/archive/list/\"><b>"+unicode(item)+"</b></a>"
            else:
                return u"<a href=\"/archive/list/"+unicode(item)+"/\">"+unicode(item)+"</a>"


@login_required
@teacher_only
@returnable
def list_archive(request, year_no=None, training_id=None, teacher=None):
    #TODO sprawdzanie czy wybrany poprawny rok
    if training_id!=None:
        tmp_result = Training.objects.filter(pk=training_id)
        if len(tmp_result)==1:
            tmp_result[0].is_archival=False
            tmp_result[0].save()
        return HttpResponseRedirect('/archive/?msg=Wybrana praktyka została przywrócona z archiwum')
    
    tmp_result = Training.objects.filter(is_archival=True)
    
    start_years = [res1.training_date.start_date.year for res1 in tmp_result if not res1.training_date is None]
    end_years = [res1.training_date.end_date.year for res1 in tmp_result if not res1.training_date is None]
    all_years = list(set(start_years+end_years))
    
    years = list([ [item] for item in all_years ])
    
    table = Table(headers=[u"Lata danych archiwalnych"],data=[[u"Wszystkie"]]+years)
    renderer = markable_archive_year_link_renderer(year_no)
    table.add_field_renderer(0, renderer.markable_archive_year_link)
    
    tmp_result = Training.objects.filter(is_archival=True)
    result = None
    msg = None
    if year_no!=None:
        year_val = unicode(int(year_no))
        if(len(year_val)>4):
            year_val=unicode(datetime.today().year)
            msg=u"Błędny numer roku, zostaną wyświetlone praktyki archiwalne z roku bieżącego"
        while len(year_val)<4:
            year_val=u"0"+year_val 
        accepted_starting_dates = Training_Date.objects.filter(start_date__gte=year_val+"-01-01").filter(start_date__lte=year_val+"-12-31")
        accepted_ending_dates = Training_Date.objects.filter(end_date__gte=year_val+"-01-01").filter(end_date__lte=year_val+"-12-31")
        accepted_training_dates = list(set(list(accepted_starting_dates)+list(accepted_ending_dates)))
        
        result = tmp_result.filter(training_date__in=accepted_training_dates)
    
    if year_no==None:
        result = tmp_result
    elif len(result)==0:
        msg=u"Brak danych dla bieżącego roku"
        
    
    return render('archive_list.html', request, 
                  {'trainings': result,
                   'years': table,
                   'msg': msg})


######################
# Settings Interface #
######################

@login_required
@teacher_or_dean_only
def edit_settings(request, teacher=None, dean=None):
    initial = {'default_insurance': Setting.default_insurance(),
               'default_insurance_company': Setting.default_insurance_company().id}
    if request.method == 'POST':
        form = SettingsForm(request.POST, initial=initial)
        if form.is_valid():
            data = form.cleaned_data
            Setting.default_insurance_company(data['default_insurance_company'])
            Setting.default_insurance(data['default_insurance'])
            return render('edit_settings.html',
                          request,
                          {'form': form,
                           'msg': u'Ustawienia zostały zapisane.'})
    else:
        form = SettingsForm(initial=initial)
    return render('edit_settings.html', request, {'form': form})

